import json
from PyQt5.QtWidgets import (
    QHBoxLayout,
    QVBoxLayout,
    QLabel,
    QHeaderView,
    QGridLayout,
    QPushButton,
    QFileDialog,
    QComboBox,
    QFrame,
    QGroupBox,
    QAbstractItemView,
    QTableWidgetItem,
    QTableWidget,
    QSpacerItem,
    QSizePolicy,
)
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject, QEvent
from PyQt5.QtGui import QPainter, QPen, QColor, QDoubleValidator
from pydantic import BaseModel, Field, field_validator

# import pandas as pd
import csv
import gui.controls.envs as envs

# import gui.controls.envs as envs
from ..dlg_model_params import DlgModelParams

# from ..dlg_mulit_instance import DlgMutliInstance
from ..c_params_table import CParamsTable

# from plugins.DUT_tiankuo.ipimas.params_model.dlg_params import DlgParams
from ..dlg_params import DlgParams
from ..util.file_operation import FileOperation
from ..custom_widget import LineEditFloat, LineEditStr, LineEditInt, SelectBox
from ..util import util_materiallibrayr_key_map
from ..utils import Utils
import pandas as pd
from .. import message_box as MBox
import chardet


class CustomTable(CParamsTable):

    def __init__(self, rows=0, columns=2, parent=None):
        super(CustomTable, self).__init__(rows=rows, columns=columns, parent=parent)
        self.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.verticalHeader().setVisible(True)


class DlgMaterialLibrary(DlgModelParams):
    materialLibrary_save_signal = pyqtSignal(object)

    def __init__(self, parent=None):
        super(DlgMaterialLibrary, self).__init__(parent)
        self.setWindowTitle("材料属性")
        self.setMinimumWidth(1000)
        self.setMinimumHeight(400)
        self.lastId = 0

        # 创建垂直布局
        layout = QHBoxLayout()
        self.widgetDict = {}

        self.data = [
            {"name": "name", "title": "名称", "type": "str", "require": True},
            {"name": "poissonRatio", "title": "泊松比", "type": "float"},
            {
                "name": "fatigueStrengthCoefficient",
                "title": "疲劳强度系数",
                "type": "float",
            },
            {
                "name": "fatigueDuctilityCoefficient",
                "title": "疲劳延性系数",
                "type": "float",
            },
            {"name": "elasticModulus", "title": "弹性模量", "type": "float"},
            {
                "name": "fatigueStrengthExponent",
                "title": "疲劳强度指数",
                "type": "float",
            },
            {
                "name": "fatigueDuctilityExponent",
                "title": "疲劳延性指数",
                "type": "float",
            },
            {
                "name": "cyclicStrengthCoefficient",
                "title": "循环强度系数",
                "type": "float",
            },
            {
                "name": "CyclicStrainHardening",
                "title": "循环应变硬化指数",
                "type": "float",
            },
            # {"name": "id", "title": "id", "type": "float"},
        ]

        self.headerLabels = []
        self.headerValues = []
        for lab in self.data:
            self.headerLabels.append(lab.get("title"))
            self.headerValues.append(lab.get("name"))

        self.table = CParamsTable(rows=0, columns=len(self.headerLabels))
        self.table.cellDoubleClicked.connect(self.cell_was_double_clicked)
        self.table.setHorizontalHeaderLabels(self.headerLabels)
        self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)
        # self.table.setColumnHidden(len(self.headerLabels) - 1, True)
        self.table.rowSetFloat([1, 2, 3, 4, 5, 6])
        # self.table.horizontalHeader().setSectionResizeMode(
        #     0, QHeaderView.Fixed
        # )  # 第一列固定
        self.table.setColumnWidth(0, 160)
        layout.addWidget(self.table)
        addBtn = QPushButton("增加")
        importBtn = QPushButton("导入")
        editBtn = QPushButton("编辑")
        delBtn = QPushButton("删除")
        self.pBtnOK.setVisible(False)
        addBtn.setFocusPolicy(Qt.NoFocus)
        importBtn.setFocusPolicy(Qt.NoFocus)
        editBtn.setFocusPolicy(Qt.NoFocus)
        delBtn.setFocusPolicy(Qt.NoFocus)
        self.pBtnCancel.setFocusPolicy(Qt.NoFocus)

        self.btnLayout.insertWidget(1, addBtn)
        self.btnLayout.insertWidget(2, importBtn)
        self.btnLayout.insertWidget(3, editBtn)
        self.btnLayout.insertWidget(4, delBtn)

        addBtn.clicked.connect(self.on_addBtn_clicked)
        importBtn.clicked.connect(self.on_importBtn_clicked)
        delBtn.clicked.connect(self.on_delBtn_clicked)
        editBtn.clicked.connect(self.on_editBtn_clicked)

        self.vbox.insertLayout(0, layout)

        self.cacheFile = "data/ipimas/uis/materialLibrary.json"
        # res = Utils.read_json(self.cacheFile)

        # envs.ipimas_updateHoneycombCore = lambda *args, **kwargs: self.__update_model(*args, **kwargs)

    def init(self, data):
        self.loadTableData(data)

    def on_addBtn_clicked(self):
        row_count = self.table.rowCount()
        other = {"existName": self.getMaterialName(self.table)}
        self.dlg = DlgParams(
            self, type="add", data=self.data, lastId=row_count, other=other, title=""
        )
        self.dlg.save_signal.connect(self.save_signal)
        self.dlg.exec_()
        self.dlg = None

    def on_importBtn_clicked(self):
        file_dialog = QFileDialog()
        file_dialog.setNameFilter("CSV files (*.csv)")
        # 设置对话框标题
        file_dialog.setWindowTitle("选择csv文件")
        # 显示对话框并获取用户选择的文件
        if file_dialog.exec_():
            # 用户点击了“打开”或“保存”，获取选中的文件路径
            file_path = file_dialog.selectedFiles()[0]
            # self.loadCsv(file_path)
            self.loadCsv(file_path)

    def loadCsv(self, filePath):
        columns = [
            "名称",
            "泊松比",
            "疲劳强度系数",
            "疲劳延性系数",
            "弹性模量",
            "疲劳强度指数",
            "疲劳延性指数",
            "循环强度系数",
            "循环应变硬化指数",
        ]
        csvData = self.processCSV(filePath, columns)
        del csvData[0]
        copyCsvData = csvData.copy()
        tableDict = self.getTableDict(self.table)
        for addRow in copyCsvData:
            if addRow[0] is not None and str(addRow[0]) in tableDict:
                addRow.append(tableDict[str(addRow[0])][7])
                tableDict[str(addRow[0])] = addRow
            else:
                # self.lastId += 1
                # addRow.append(self.lastId)
                tableDict[str(addRow[0])] = addRow
        self.table.setRowCount(0)
        for _, row_data in tableDict.items():
            self.table.addRow(row_data)
        self.saveData()

    def processCSV(self, file_path, columns):
        """处理CSV文件并按指定顺序生成二维数组"""

        try:
            # 检测并读取CSV文件
            encoding = self.detect_encoding(file_path)
            try:
                df = pd.read_csv(file_path, encoding=encoding)
            except UnicodeDecodeError:
                encodings = ["utf-8", "gbk", "gb2312", "gb18030", "big5", "latin1"]
                for enc in encodings:
                    try:
                        df = pd.read_csv(file_path, encoding=enc)
                        break
                    except UnicodeDecodeError:
                        continue
                else:
                    raise ValueError("无法确定文件编码")

            # 初始化结果数组（第一行为列名）
            result_array = [columns.copy()]

            # 获取CSV中存在的列
            existing_columns = [col for col in columns if col in df.columns]
            missing_columns = set(columns) - set(existing_columns)

            # 处理每一行数据
            for _, row in df.iterrows():
                new_row = []
                for col in columns:
                    if col in df.columns:
                        value = str(row[col]) if pd.notna(row[col]) else ""
                    else:
                        value = ""
                    new_row.append(value)
                result_array.append(new_row)

            return result_array

        except Exception as e:
            MBox.warning(f"处理CSV文件时出错:\n{str(e)}")
            return None

    def getTableDict(self, table):
        dict = {}
        for row in range(table.rowCount()):
            list = []
            for col in range(table.columnCount()):
                item = table.item(row, col)
                if item is not None:
                    list.append(table.getRuleValue(item.text(), col))
                else:
                    list.append(None)
            item0 = table.item(row, 0)
            dict[item0.text()] = list
        return dict

    # def load_excel(self, filePath):
    #     try:
    #         data = []
    #         excelData = pd.read_excel(filePath, header=0, usecols=["名称","泊松比","疲劳强度系数","疲劳延性系数","弹性模量","疲劳强度指数","疲劳延性指数"])
    #         for index, row in excelData.iterrows():
    #             data.append([
    #                 row["寿命值"],
    #             ])
    #         self.widgetDict['statisticsTable'].addMulitRows(data)
    #     except FileNotFoundError:
    #         print(f"Error: 文件 '{filePath}' 未找到.")

    def on_delBtn_clicked(self):
        self.table.deleteSelectedRow()
        self.saveData()

    def on_editBtn_clicked(self):
        other = {"existName": self.getMaterialName(self.table, isAlert=True)}
        data = self.table.editSelectedRow()
        if data:
            self.dlg = DlgParams(
                self, type="alert", data=self.data, initData=data, other=other
            )
            self.dlg.alert_signal.connect(self.alert_signal)
            self.dlg.exec_()
            self.dlg = None

    def save_signal(self, data):
        # self.lastId = data[len(data) - 1]
        self.table.addRow(data)
        self.saveData()

    def alert_signal(self, data):
        self.table.updateRowWithData(data)
        self.saveData()

    def cell_was_double_clicked(self, row, column):
        other = {"existName": self.getMaterialName(self.table, isAlert=True)}
        data = self.table.editSelectedRow()
        self.dlg = DlgParams(
            self, type="alert", data=self.data, initData=data, other=other
        )
        self.dlg.alert_signal.connect(self.alert_signal)
        self.dlg.exec_()
        self.dlg = None

    def loadTableData(self, res):
        self.table.setRowCount(0)
        if res:
            titleMap = self.headerValues
            for row_data in res:
                row_data = util_materiallibrayr_key_map.convertKey(row_data, 0)
                values = []
                for title in titleMap:
                    values.append(row_data.get(title) or "")
                self.table.addRow(values)

    # def loadData(self, data):
    #     self.table.setRowCount(0)
    #     if data is None:
    #         return
    #     res = util_key_map.convertKey(data, 0, True)
    #     # res = FileOperation.read_json(self.cacheFile)
    #     if res:
    #         for row_data in res:
    #             row_data["名称"] = row_data["材料名称"]
    #             del row_data["材料名称"]
    #             values = [
    #                 row_data[key] for key in self.headerLabels if key in row_data
    #             ]  # 先将id过滤
    #             # while len(values) < 10:
    #             #     values.append("")
    #             # values[9] = row_data.get("id")  # 再将id加入指定行
    #             self.table.addRow(values)
    #     # if "lastId" in res and res.get("lastId"):
    #     #     self.lastId = float(res.get("lastId"))

    def saveData(self):
        data = []
        for i in range(self.table.rowCount()):
            row_dict = {}
            for j in range(self.table.columnCount()):
                item = self.table.item(i, j)
                if item:
                    if j == 0:
                        row_dict["材料名称"] = item.text()
                    else:
                        row_dict[self.headerValues[j]] = (
                            float(item.text()) if item.text() else None
                        )
                else:
                    row_dict[self.headerValues[j]] = None
                row_dict = util_materiallibrayr_key_map.convertKey(row_dict, 1)
                # row_dict['材料类型'] = '蜂窝芯子'
            data.append(row_dict)
        res = data
        FileOperation.write_json(self.cacheFile, res)
        # filtered_data = [{k: v for k, v in item.items() if k != "id"} for item in data]
        self.materialLibrary_save_signal.emit(res)

    def getMaterialName(self, table, isAlert=False):
        first_column_data = []
        row_index = -1
        selected_items = self.table.selectedItems()
        if selected_items and isAlert:
            row_index = selected_items[0].row()
        for i in range(table.rowCount()):
            if i == row_index:
                continue
            item = table.item(i, 0)  # 获取第一列的单元格项
            first_column_data.append(item.text())  # 添加文本到列表
        return first_column_data

    def closeEvent(self, event):
        DlgMaterialLibrary._shown = False  # 使用类名访问类属性
        DlgMaterialLibrary._instance = None  # 清除实例引用
        event.accept()

    def detect_encoding(self, file_path):
        """自动检测文件编码"""
        with open(file_path, "rb") as f:
            rawdata = f.read(10000)
            result = chardet.detect(rawdata)
            return result["encoding"]
